package cn.demoncat.util.redis.entity;

import cn.demoncat.util.lang.constant.StringConstant;
import cn.demoncat.util.web.TokenUtil;

/**
 * Redis Lock Key 分布式锁 常量
 *
 * @author 延晓磊
 *
 * @since 2020年1月15日
 */
public class RedisLock {

	// 默认锁前缀名
	public static final String LOCK_NAME = "LOCK:";

	// 缓存键/键前缀
	private String key;
	/**
	 * 锁的自动过期秒数：0 不过期，执行完成后主动释放（顺序执行）；非0 到期自动释放，执行完成后不主动释放（间隔执行）
	 *
	 * 场景：lock,tryLock
	 */
	private int exp;
	/**
	 * 尝试获取锁的秒数：0表示只尝试1次
	 *
	 * 场景：tryLock,tryAcquireSemaphore
	 */
	private int tryTime;
	/**
	 * 阻塞等待锁的秒数：0表示永久等待
	 *
	 * 场景：countDownLatch
	 */
	private int awaitTime;
	// 事务：是否在事务提交后执行非阻塞无返回的锁操作，如解锁、释放资源
	private boolean tx;
	// 粒度：Token，用户，全局（默认）
	private String level = Level.ALL;
	// 类型：尝试加锁（根据tryTime设置进行尝试，失败时放弃执行）、阻塞加锁（默认）
	private boolean tryLock;

	/**
	 * 粒度
	 */
	public interface Level{
		String ALL = "0";
		String TOKEN = "1";
		String USER = "2";
	}

	public RedisLock() {
		super();
	}

	/**
	 * 构建常量
	 *
	 * @param key	键前缀
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年1月15日
	 */
	public RedisLock(String key) {
		this.setKey(key);
	}

	/**
	 * 构建实例（拼接KEY）
	 * 
	 * @param id	拼接在key后
	 * 
	 * @return 新的RedisLock
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年1月15日
	 */
	public RedisLock build(Object id) {
		RedisLock data = new RedisLock();
		data.key = this.key(id);
		data.exp = this.exp;
		data.level = this.level;
		data.tx = this.tx;
		data.tryLock = this.tryLock;
		data.tryTime = this.tryTime;
		data.awaitTime = this.awaitTime;
		return data;
	}
	
	/**
	 * 获取Key
	 * 
	 * @param id	拼接在key后
	 * 
	 * @return this.key + id
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年1月15日
	 */
	public String key(Object id) {
		return this.key + id;
	}

	/**
	 * 获取缓存键
	 *
	 * @return key + levelValue
	 */
	public String getKey() {
		switch (this.level) {
			case Level.TOKEN:
				// 会话锁
				return this.key + StringConstant.COLON + TokenUtil.getCToken();
			case Level.USER:
				// 用户锁
				return this.key + StringConstant.COLON + TokenUtil.getUserId();
			default:
				// 全局锁
				return this.key;
		}
	}

	/**
	 * 设置缓存键/前缀
	 *
	 * @param key
	 */
	public RedisLock setKey(String key) {
		if (key.startsWith(LOCK_NAME)) {
			this.key = key;
		}else{
			this.key = LOCK_NAME + key;
		}
		return this;
	}

	public int getExp() {
		return exp;
	}

	/**
	 * 锁的自动过期时间
	 *
	 * @param exp	0 不过期，执行完成后主动释放；非0 到期自动释放，执行完成后不主动释放
	 * @return
	 */
	public RedisLock setExp(int exp) {
		if (exp < 0) {
			exp = 0;
		}
		this.exp = exp;
		return this;
	}

	public int getTryTime() {
		return tryTime;
	}

	/**
	 * 设置尝试获取锁的秒数
	 * @param tryTime	0表示只尝试1次
	 * @return
	 */
	public RedisLock setTryTime(int tryTime) {
		if (tryTime < 0) {
			tryTime = 0;
		}
		this.tryTime = tryTime;
		return this;
	}

	public int getAwaitTime() {
		return awaitTime;
	}

	/**
	 * 阻塞等待锁的秒数
	 *
	 * @param awaitTime	0表示永久等待
	 * @return
	 */
	public RedisLock setAwaitTime(int awaitTime) {
		if (awaitTime < 0) {
			awaitTime = 0;
		}
		this.awaitTime = awaitTime;
		return this;
	}

	public boolean isTx() {
		return tx;
	}

	/**
	 * 设置事务
	 *
	 * @param tx    是否在事务提交后执行非阻塞无返回的锁操作，如解锁、释放资源
	 * @return
	 */
	public RedisLock setTx(boolean tx) {
		this.tx = tx;
		return this;
	}

	public String getLevel() {
		return level;
	}

	/**
	 * 设置粒度
	 *
	 * @param level	Token，用户，全局（默认）
	 * @return
	 */
	public RedisLock setLevel(String level) {
		this.level = level;
		return this;
	}

	public boolean isTryLock() {
		return tryLock;
	}

	public RedisLock setTryLock(boolean tryLock) {
		this.tryLock = tryLock;
		return this;
	}
}
